#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

const int SIZE=10;
#define MAX 10
#define MAX_WIDTH (2*MAX+1)
const char FG = 'X';
const char BG = ' ';
const unsigned INTERVAL = 125000;

struct Peg 
{
  int height;
  unsigned stack[MAX];
};

void initialize( struct Peg * peg, int height )
{
  int i;
  for ( i = 0; i < MAX; i++ ) {
    peg->stack[i] = i < height ? height-i : 0;
  }
  peg->height = height;
}

void move( struct Peg* a, struct Peg* b)
{
  b->stack[b->height] = a->stack[a->height-1];
  b->height++;
  a->stack[a->height-1] = 0;
  a->height--;
}

void disk_string( char *result, unsigned val )
{
  int i;
  const unsigned st = MAX_WIDTH/2-val;
  const unsigned en = MAX_WIDTH/2+val;
  for ( i=0; i < MAX_WIDTH; i++ ) {
    result[i] = ( i > st && i < en ) ? FG : BG;
  }
  result[MAX_WIDTH] = '\0';
}
char disks[MAX+1][MAX_WIDTH+1];

void print_pegs( struct Peg *pegs[] )
{
  int tier, i;
  system("clear");

  for ( tier = MAX; tier > 0; tier-- ) {
    for ( i = 0; i<3; i++ ) {
      printf("%s", disks[pegs[i]->stack[tier-1]]);
    }
    printf("\n");
  }
  usleep(INTERVAL);
}

struct Peg a,b,c;
struct Peg *pegs[] = { &a, &b, &c };

void hanoi( int size, struct Peg *f, struct Peg* t, struct Peg* u )
{
  if ( size <= 1 ) {
    move( f, t );
    print_pegs( pegs );
  } 
  else {
    hanoi( size-1, f, u, t );
    hanoi( 1, f, t, u );
    hanoi( size-1, u, t, f );
  }
}

int main( int argc, char* argv[] )
{
  int i;
  for ( i = 0; i < MAX+1; i++ ) {
    disk_string( disks[i], i );
  }

  initialize( &a, SIZE );
  initialize( &b, 0 );
  initialize( &c, 0 );

  print_pegs( pegs );
  while ( 1 ) {
    sleep(1);
    hanoi( SIZE, &a, &b, &c );
    sleep(1);
    hanoi( SIZE, &b, &c, &a );
    sleep(1);
    hanoi( SIZE, &c, &a, &b );
  }
  return 0;
}
